package com.rm.zeyou.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.rm.zeyou.constant.CommonConstants;
import com.rm.zeyou.constant.NumberConstants;
import com.rm.zeyou.entity.*;
import com.rm.zeyou.exception.ErrorCodeException;
import com.rm.zeyou.exception.ErrorCodeExceptionEnum;
import com.rm.zeyou.mapper.*;
import com.rm.zeyou.pay.wxpay.constants.WechatPayOutConstants;
import com.rm.zeyou.pay.wxpay.transfer.service.TransferNewService;
import com.rm.zeyou.pay.wxpay.transfer.vo.TransferQueryResponse;
import com.rm.zeyou.response.ApiRestResponse;
import com.rm.zeyou.service.ChannelPayoutDetailService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rm.zeyou.util.check.CheckEmptyUtil;
import com.rm.zeyou.vo.request.SalesmanPayoutListVo;
import com.rm.zeyou.vo.request.SelectUserPayoutIndexVo;
import com.rm.zeyou.vo.response.ConfirmPayoutResponseVo;
import com.rm.zeyou.vo.response.SalesmanPayoutListResponseVo;
import com.rm.zeyou.vo.response.SelectUserPayoutIndexResponseVo;
import com.rm.zeyou.vo.response.UserPayoutVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 渠道商提现记录表 服务实现类
 * </p>
 *
 * @author YanYang
 * @since 2025-03-12 15:55:07
 */
@Service
public class ChannelPayoutDetailServiceImpl extends ServiceImpl<ChannelPayoutDetailMapper, ChannelPayoutDetail> implements ChannelPayoutDetailService {
    @Resource
    private ChannelPayoutDetailMapper channelPayoutDetailMapper;

    @Resource
    private TransferNewService transferNewService;
    @Resource
    private UserBackMapper userBackMapper;
    @Resource
    private ChannelMerchantsMapper channelMerchantsMapper;
    @Resource
    private ChannelConsumeDetailMapper channelConsumeDetailMapper;
    @Resource
    private PayoutConfigMapper payoutConfigMapper;
    @Resource
    private UserZfbCountMapper userZfbCountMapper;
    @Resource
    private AgreementConfigMapper agreementConfigMapper;
    @Resource
    private PayoutDictConfigMapper payoutDictConfigMapper;
    @Resource
    private WxpayConfigMapper wxpayConfigMapper;
    @Resource
    private ApplicationConfigMapper applicationConfigMapper;

    @Override
    public ApiRestResponse<SelectUserPayoutIndexResponseVo> selectChannelPayoutIndex(User user, SelectUserPayoutIndexVo requestVo) {
        SelectUserPayoutIndexResponseVo responseVo = new SelectUserPayoutIndexResponseVo();
        BigDecimal payoutFee = new BigDecimal(payoutDictConfigMapper.selectValue("payout_fee")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal payoutTax = new BigDecimal(payoutDictConfigMapper.selectValue("payout_tax")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal minPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("min_payout_price"));
        BigDecimal maxPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("max_payout_price"));

        responseVo.setMinPayoutPrice(minPayoutPrice);
        responseVo.setMaxPayoutPrice(maxPayoutPrice);
        //收入金额
        ChannelMerchants channelMerchants = channelMerchantsMapper.selectOne(new LambdaQueryWrapper<ChannelMerchants>()
                .eq(ChannelMerchants::getUserId, user.getId()));
        BigDecimal addAmount = channelConsumeDetailMapper.selectAddAmount(channelMerchants.getId());
        //已提现金额
        BigDecimal payoutAmount = channelConsumeDetailMapper.selectPayoutAmount(channelMerchants.getId());
        responseVo.setUserBalance(addAmount.subtract(payoutAmount));
        responseVo.setTaxPrice(requestVo.getPayoutPrice().multiply(payoutTax));
        responseVo.setFeePrice(requestVo.getPayoutPrice().multiply(payoutFee));

        int userBackCount = userBackMapper.selectCount(new LambdaQueryWrapper<UserBack>()
                .eq(UserBack::getUserId, user.getId())).intValue();
        if (userBackCount > 0) {
            responseVo.setIsBindBack(NumberConstants.ONE_CONSTANTS);
        } else {
            responseVo.setIsBindBack(NumberConstants.ZERO_CONSTANTS);
        }

        if (CheckEmptyUtil.isEmpty(user.getOpenId())){
            responseVo.setIsBindWx(NumberConstants.ZERO_CONSTANTS);
        }else {
            responseVo.setIsBindWx(NumberConstants.ONE_CONSTANTS);
        }

        UserZfbCount userZfbCount = userZfbCountMapper.selectOne(new LambdaQueryWrapper<UserZfbCount>().eq(UserZfbCount::getUserId, user.getId()));
        if (CheckEmptyUtil.isEmpty(userZfbCount)){
            responseVo.setIsBindZfb(NumberConstants.ZERO_CONSTANTS);
        }else {
            responseVo.setIsBindZfb(NumberConstants.ONE_CONSTANTS);
        }
        String payoutIllustrate = agreementConfigMapper.selectValue("payout_illustrate");
        responseVo.setPayoutIllustrate(payoutIllustrate);

        return ApiRestResponse.success(responseVo);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> channelPayout(User user, UserPayoutVo requestVo) {
        PayoutConfig payoutConfig = payoutConfigMapper.selectById(requestVo.getPayoutWayId());
        if (CheckEmptyUtil.isEmpty(payoutConfig) && requestVo.getPayoutWayId() !=4) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_WAY_EMPTY);
        }
        if (requestVo.getPayoutWayId() == 4) {
            UserBack userBack = userBackMapper.selectById(requestVo.getUserBackId());
            if (CheckEmptyUtil.isEmpty(userBack)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.USER_BACK_EMPTY);
            }
        }

        if (requestVo.getPayoutWayId() == 3) {
            UserZfbCount userZfbCount = userZfbCountMapper.selectOne(new LambdaQueryWrapper<UserZfbCount>().eq(UserZfbCount::getUserId, user.getId()));
            if (CheckEmptyUtil.isEmpty(userZfbCount)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.ZFB_COUNT_EMPTY);
            }
        }


        if (requestVo.getPayoutWayId() == 2) {
            String openId;
            if (requestVo.getWithdrawalsEnvironment().equals("H5")) {
                openId = user.getOpenId();
            } else {
                openId = user.getAppOpenId();
            }
            if (CheckEmptyUtil.isEmpty(openId)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.NOT_BIND_WX);
            }
        }
        BigDecimal payoutFee = new BigDecimal(payoutDictConfigMapper.selectValue("payout_fee")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal payoutTax = new BigDecimal(payoutDictConfigMapper.selectValue("payout_tax")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal minPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("min_payout_price"));
        BigDecimal maxPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("max_payout_price"));
        if (requestVo.getPayoutPrice().compareTo(minPayoutPrice) < 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_MIN_PRICE.getCode(), String.format(ErrorCodeExceptionEnum.PAYOUT_MIN_PRICE.getMsg(), minPayoutPrice.toPlainString()));
        }

        if (requestVo.getPayoutPrice().compareTo(maxPayoutPrice) > 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_MAX_PRICE.getCode(), String.format(ErrorCodeExceptionEnum.PAYOUT_MAX_PRICE.getMsg(), minPayoutPrice.toPlainString()));
        }
        //收入金额
        ChannelMerchants channelMerchants = channelMerchantsMapper.selectOne(new LambdaQueryWrapper<ChannelMerchants>()
                .eq(ChannelMerchants::getUserId, user.getId()));
        BigDecimal addAmount = channelConsumeDetailMapper.selectAddAmount(channelMerchants.getId());
        //已提现金额
        BigDecimal payoutAmount = channelConsumeDetailMapper.selectPayoutAmount(channelMerchants.getId());
        //可提现金额
        BigDecimal canPayoutPrice = addAmount.subtract(payoutAmount);
        if (requestVo.getPayoutPrice().compareTo(canPayoutPrice) > 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_PRICE_ENOUGH);
        }

        ChannelPayoutDetail channelPayoutDetail = new ChannelPayoutDetail();
        channelPayoutDetail.setChannelId(channelMerchants.getId());
        channelPayoutDetail.setPayoutType(Math.toIntExact(requestVo.getPayoutWayId()));
        channelPayoutDetail.setPayoutPrice(requestVo.getPayoutPrice());
        BigDecimal fee = requestVo.getPayoutPrice().multiply(payoutFee);
        channelPayoutDetail.setPayoutFee(fee);
        BigDecimal tax = requestVo.getPayoutPrice().multiply(payoutTax);
        channelPayoutDetail.setPayoutTax(tax);
        channelPayoutDetail.setRealPrice(requestVo.getPayoutPrice().subtract(fee).subtract(tax));
        if (requestVo.getPayoutWayId() == 4) {
            UserBack userBack = userBackMapper.selectById(requestVo.getUserBackId());
            channelPayoutDetail.setBackName(userBack.getBackName());
            channelPayoutDetail.setBackUserName(userBack.getBackUserName());
            channelPayoutDetail.setBackIdcard(userBack.getBackIdcard());
            channelPayoutDetail.setBackBranch(userBack.getBackBranch());
        }
        channelPayoutDetail.setWithdrawalsEnvironment(requestVo.getWithdrawalsEnvironment());
        channelPayoutDetailMapper.insert(channelPayoutDetail);


        ChannelConsumeDetail channelConsumeDetail = new ChannelConsumeDetail();
        channelConsumeDetail.setChannelId(channelMerchants.getId());
        channelConsumeDetail.setChannelPayoutId(channelPayoutDetail.getId());
        channelConsumeDetail.setConsumptionPrice(requestVo.getPayoutPrice());
        channelConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_PAYOUT);
        channelConsumeDetail.setConsumptionDescribe("提现审核中");
        int insert = channelConsumeDetailMapper.insert(channelConsumeDetail);


        return ApiRestResponse.success(insert);
    }

    @Override
    public ApiRestResponse<PageInfo<SalesmanPayoutListResponseVo>> channelPayoutList(User user, SalesmanPayoutListVo requestVo) {
        ChannelMerchants channelMerchants = channelMerchantsMapper.selectOne(new LambdaQueryWrapper<ChannelMerchants>()
                .eq(ChannelMerchants::getUserId, user.getId()));
        List<SalesmanPayoutListResponseVo> voList = new ArrayList<>();
        PageHelper.startPage(requestVo.getPageNum(), requestVo.getPageSize());
        List<ChannelPayoutDetail> channelPayoutDetails = channelPayoutDetailMapper.selectList(new LambdaQueryWrapper<ChannelPayoutDetail>()
                .eq(ChannelPayoutDetail::getChannelId, channelMerchants.getId())
                .orderByDesc(ChannelPayoutDetail::getCreateTime));
        if (!CheckEmptyUtil.isEmpty(channelPayoutDetails)) {
            PageInfo<ChannelPayoutDetail> source = new PageInfo<>(channelPayoutDetails);
            PageInfo<SalesmanPayoutListResponseVo> target = new PageInfo<>();
            source.getList().forEach(item -> {
                SalesmanPayoutListResponseVo vo = new SalesmanPayoutListResponseVo();
                vo.setPayoutPrice(item.getPayoutPrice());
                vo.setPayoutFee(item.getPayoutFee());
                vo.setPayoutTax(item.getPayoutTax());
                vo.setRealPrice(item.getRealPrice());
                vo.setPayoutStatus(item.getPayoutStatus());
                vo.setFalseReason(item.getFalseReason());
                vo.setCreateTime(item.getCreateTime());
                vo.setPayoutType(item.getPayoutType());
                voList.add(vo);
            });
            target.setList(voList);
            return ApiRestResponse.success(target);
        }
        return ApiRestResponse.success(new PageInfo<>());
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void updateChannelWithdrawals() {
        List<ChannelPayoutDetail> channelPayoutDetails = channelPayoutDetailMapper.selectNotSuccessOrFailList();
        if (!CheckEmptyUtil.isEmpty(channelPayoutDetails)) {
            for (ChannelPayoutDetail channelPayoutDetail : channelPayoutDetails) {
                TransferQueryResponse transferQueryResponse = transferNewService.queryTransferByOutBillNo(channelPayoutDetail.getWxWithdrawalsNo());
                if (!CheckEmptyUtil.isEmpty(transferQueryResponse)) {
                    channelPayoutDetail.setWxWithdrawalsStatus(transferQueryResponse.getState());
                    ChannelConsumeDetail channelConsumeDetail = channelConsumeDetailMapper.selectOne(new LambdaQueryWrapper<ChannelConsumeDetail>()
                            .eq(ChannelConsumeDetail::getChannelPayoutId, channelPayoutDetail.getId()));
                    if (transferQueryResponse.getState().equals(WechatPayOutConstants.SUCCESS)) {
                        channelPayoutDetail.setPayoutStatus(NumberConstants.ONE_CONSTANTS);
                        channelConsumeDetail.setConsumptionDescribe("提现成功");
                    }

                    if (transferQueryResponse.getState().equals(WechatPayOutConstants.FAIL)) {
                        channelPayoutDetail.setPayoutStatus(NumberConstants.TWO_CONSTANTS);
                        channelConsumeDetail.setConsumptionDescribe("提现失败");
                    }
                    channelPayoutDetailMapper.updateById(channelPayoutDetail);
                    channelConsumeDetailMapper.updateById(channelConsumeDetail);
                }
            }
        }
    }

    @Override
    public ApiRestResponse<List<ConfirmPayoutResponseVo>> channelConfirmPayout(User user) {
        ChannelMerchants channelMerchants = channelMerchantsMapper.selectOne(new LambdaQueryWrapper<ChannelMerchants>()
                .eq(ChannelMerchants::getUserId, user.getId()));
        if (ObjectUtil.isEmpty(channelMerchants)) {
            return ApiRestResponse.success(new ArrayList<>());
        }
        List<ChannelPayoutDetail> channelPayoutDetails = channelPayoutDetailMapper.selectList(new LambdaQueryWrapper<ChannelPayoutDetail>()
                .eq(ChannelPayoutDetail::getWxWithdrawalsStatus, "WAIT_USER_CONFIRM")
                .eq(ChannelPayoutDetail::getChannelId,channelMerchants.getId()));
        List<ConfirmPayoutResponseVo> responseVoList = new ArrayList<>(channelPayoutDetails.size());
        if (!CheckEmptyUtil.isEmpty(channelPayoutDetails)) {
            for (ChannelPayoutDetail channelPayoutDetail : channelPayoutDetails) {
                ConfirmPayoutResponseVo responseVo = new ConfirmPayoutResponseVo();
                responseVo.setId(channelPayoutDetail.getId());
                responseVo.setPackageInfo(channelPayoutDetail.getPackageInfo());
                String mchId = wxpayConfigMapper.selectOneData("mchId");
                responseVo.setMuchId(mchId);
                String accountAppid = applicationConfigMapper.selectOneData("account_appid");
                responseVo.setH5Appid(accountAppid);
                String appAppid = applicationConfigMapper.selectOneData("app_appid");
                responseVo.setAppAppid(appAppid);
                responseVoList.add(responseVo);
            }
        }
        return ApiRestResponse.success(responseVoList);
    }
}
